package com.maple.common.widget.step

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.Dimension
import androidx.annotation.IntDef
import androidx.core.content.withStyledAttributes
import com.maple.common.R
import com.maple.common.log.LogUtil
import com.maple.common.ext.dpToPx
import com.maple.common.widget.step.StepControlView.LineMode.Companion.LINE_DOTTED
import com.maple.common.widget.step.StepControlView.LineMode.Companion.LINE_SOLID
import kotlin.math.ceil


/**
 * Tip:步骤控制器
 * Create by SeVen on 2025/3/6 14:27
 */
class StepControlView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    @LineMode
    private var lineMode: Int = LINE_SOLID

    /**
     *
     * Step
     */
    private var step: Int = 0

    /**
     * Select step
     */
    private var selectStep = 0

    /**
     * 设置最大的步数,默认的最大步数为4
     * Max step
     */
    private var maxStep = 4

    /**
     * 步数内容
     * Step content
     */
    private var stepText: Array<String> = arrayOf("Step 1", "Step 2", "Step 3", "Step 4")

    /**
     * 选择器的文字大小 默认12sp
     * Select text size
     */
    @Dimension(unit = Dimension.SP)
    private var stepTextSize = 12f

    /**
     * 文字与上部分之间的间隔为,默认为0
     * Step text padding
     */
    @Dimension(unit = Dimension.DP)
    private var stepTextPadding = 0f

    /**
     *选择器圆形的半径 默认10dp
     * Step circle radius
     */
    @Dimension(unit = Dimension.DP)
    private var stepCircleRadius = 10f

    /**
     * 当前选择的步骤的半径，默认为12dp
     * Select step circle radius
     */
    @Dimension(unit = Dimension.DP)
    private var selectStepCircleRadius = 12f

    /**
     * 步骤之间间隔
     * Step space
     */
    @Dimension(unit = Dimension.DP)
    private var stepSpace: Float = 12f

    /**
     *  上一步的颜色
     * Pre step color
     */
    @ColorInt
    private var preStepColor = Color.BLUE

    /**
     * 当前步数的文字颜色
     * Step text color
     */
    @ColorInt
    private var stepColor = Color.GREEN

    /**
     * 下一步的颜色
     * Next step color
     */
    @ColorInt
    private var nextStepColor = Color.GRAY

    /**
     * Pre line color
     */
    @ColorInt
    private var preLineColor = Color.BLUE

    /**
     * 下一步
     * Next line color
     */
    @ColorInt
    private var nextLineColor = Color.GRAY

    /**
     * Circle paint
     */
    private var circlePaint = Paint(Paint.ANTI_ALIAS_FLAG)

    /**
     * Step paint
     */
    private var stepTextPaint = Paint()

    /**
     *
     * Lie paint
     */
    private var linePaint = Paint(Paint.ANTI_ALIAS_FLAG)

    /**
     * 每个单位的宽度
     * Unit x
     */
    private var unitX: Float = 0f

    /**
     * 圆环中间的对勾的路径
     * Check path
     */
    private val checkPath = Path() // 定义勾的路径


    /**
     * 文本缓存分割，当文字的宽度小于圆的直径时以圆的边界为主
     * 反之以文本的边界为主
     * Text bounds cache
     */
    private val textBoundsCache = mutableListOf<RectF>()

    /**
     * 点击控制
     * On step click listener
     */
    private var onStepClickListener: ((step: Int, selectStep: Int) -> Unit)? = null

    fun setOnStepClickListener(onStepClickListener: ((step: Int, selectStep: Int) -> Unit)?) {
        this.onStepClickListener = onStepClickListener
    }

    init {
        initAttr(context, attrs, defStyleAttr)

        initPaint()
    }

    private fun initPaint() {
        linePaint.also {
            it.setColor(nextLineColor)
            it.strokeWidth = 5f
            it.style = Paint.Style.STROKE
            if (lineMode == LINE_DOTTED) {
                // 实线和空白的长度
                val intervals = floatArrayOf(dpToPx(context, 2f), dpToPx(context, 2f))
                linePaint.setPathEffect(DashPathEffect(intervals, 0f))
            }
        }

        circlePaint.also {
            it.setColor(nextStepColor)
            it.strokeWidth = 5f
            it.style = Paint.Style.STROKE
        }

        stepTextPaint.also {
            it.setColor(nextStepColor)
            it.style = Paint.Style.FILL
            it.textSize = stepTextSize
        }
    }

    /**
     * Init attr
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private fun initAttr(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
        context.withStyledAttributes(attrs, R.styleable.StepView) {
            lineMode = getInteger(R.styleable.StepView_sv_line_mode, 0)

            step = getInteger(R.styleable.StepView_sv_step, 0)
            selectStep = getInteger(R.styleable.StepView_sv_selectStep, 0)
            stepTextSize = getDimension(
                R.styleable.StepView_sv_stepTextSize,
                dpToPx(context, 12.0f)
            )
            stepTextPadding =
                getDimension(R.styleable.StepView_sv_stepTextPadding, dpToPx(context, 0f))

            stepCircleRadius =
                getDimension(R.styleable.StepView_sv_pre_circleRadius, dpToPx(context, 10.0f))
            selectStepCircleRadius =
                getDimension(
                    R.styleable.StepView_sv_select_circleRadius,
                    dpToPx(context, 12.0f)
                )

            preStepColor = getColor(R.styleable.StepView_sv_pre_stepColor, Color.BLUE)
            stepColor = getColor(R.styleable.StepView_sv_stepColor, Color.GREEN)
            nextStepColor = getColor(R.styleable.StepView_sv_next_stepColor, Color.GRAY)

            preLineColor = getColor(R.styleable.StepView_sv_pre_line_color, Color.BLUE)
            nextLineColor = getColor(R.styleable.StepView_sv_next_line_color, Color.GRAY)

            // 验证是否是数组资源
            val stepTextResources: Int =
                getResourceId(R.styleable.StepView_sv_stepText, 0)
            if (stepTextResources != 0) {
                try {
                    val resources = context.resources
                    // 验证资源类型是否为数组
                    require(resources.getResourceTypeName(stepTextResources) == "array") {
                        "sv_stepText must reference an array resource (R.array.xxxxx)"
                    }
                    // 加载数组资源
                    stepText = resources.getStringArray(stepTextResources)
                } catch (e: Exception) {
                    throw IllegalArgumentException("Invalid resource type for sv_stepText", e)
                }
            }
        }
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //计算当前模式
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)

        val bgWidth: Int = if (widthMode == MeasureSpec.EXACTLY) {
            MeasureSpec.getSize(widthMeasureSpec)
        } else { //设置默认值为当前屏幕的width的最大值
            widthMeasureSpec
        }
        //高度设置无效，根据当前内容设置高度
        // 高度计算文字最大的宽度，如果不需要换行则显示一行，多行则需要显示多行的高度,
        // 最多的高度为俩行的高度，
        // 多余的文字显示。。。
        val pair: Pair<Int, Int> = findLongestStringAndMeasure(stepText)
        val bgHeight = if (bgWidth / 4 - stepSpace > pair.first) {
            (selectStepCircleRadius * 2 + paddingTop + paddingBottom + pair.second + stepTextPadding).toInt() + dpToPx(
                context,
                4
            )
        } else {
            //上下俩行的间隔为3dp
            (selectStepCircleRadius * 2 + paddingTop + paddingBottom + pair.second * 2 + stepTextPadding).toInt() + dpToPx(
                context,
                7
            )
        }
        setMeasuredDimension(bgWidth, bgHeight)
        maxStep = stepText.size
        unitX = (bgWidth.toFloat() - paddingStart - paddingEnd).div(maxStep)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 清空缓存
        textBoundsCache.clear()
        drawStep(canvas)
        drawStepText(canvas)
    }

    /**
     * 绘制圆形
     * Draw circle
     *
     * @param canvas
     */
    private fun drawStep(canvas: Canvas) {
        for (i in 0 until maxStep) {
            // 计算圆心位置
            val cx = calculateCircleCenterX(i)
            val cy = calculateCircleCenterY()

            // 设置圆的颜色
            circlePaint.color = getDrawColor(i)

            // 设置圆的半径
            val radius = if (i + 1 == selectStep) selectStepCircleRadius else stepCircleRadius

            // 绘制圆
            canvas.drawCircle(cx, cy, radius, circlePaint)

            // 绘制勾
            drawCheck(canvas, cx, cy)

            // 绘制圆与圆之间的连接线
            if (i > 0) {
                if (i > step - 1) {
                    linePaint.setColor(nextLineColor)
                } else {
                    linePaint.setColor(preLineColor)
                }
                drawConnectingLine(canvas, i, cy)
            }
        }
    }

    /**
     * 计算圆心的 X 坐标
     *
     * @param index 当前步骤索引
     * @return 圆心的 X 坐标
     */
    private fun calculateCircleCenterX(index: Int): Float {
        return unitX * index + unitX / 2 + paddingStart - dpToPx(context, 2)
    }


    /**
     * 获取圆的颜色
     *
     * @param index 当前步骤索引
     * @return 圆的颜色
     */
    private fun getDrawColor(index: Int): Int {
        return when {
            index + 1 == step -> stepColor
            index + 1 < step -> preStepColor
            else -> nextStepColor
        }
    }

    /**
     * 绘制圆与圆之间的连接线
     *
     * @param canvas 画布
     * @param index 当前步骤索引
     * @param centerY 圆心的 Y 坐标
     */
    private fun drawConnectingLine(canvas: Canvas, index: Int, centerY: Float) {
        val lineStartX = calculateLineStartX(index)
        val lineStopX = calculateLineStopX(index)
        canvas.drawLine(lineStartX, centerY, lineStopX, centerY, linePaint)
    }

    /**
     * 计算连接线的起点 X 坐标
     *
     * @param index 当前步骤索引
     * @return 连接线的起点 X 坐标
     */
    private fun calculateLineStartX(index: Int): Float {
        return unitX / 2 + selectStepCircleRadius + unitX * (index - 1) + dpToPx(
            context,
            4
        ) + paddingStart
    }

    /**
     * 计算连接线的终点 X 坐标
     *
     * @param index 当前步骤索引
     * @return 连接线的终点 X 坐标
     */
    private fun calculateLineStopX(index: Int): Float {
        return (unitX / 2 + unitX) - selectStepCircleRadius + unitX * (index - 1) - dpToPx(
            context,
            4
        ) + paddingStart
    }

    /**
     * 计算圆心的 Y 坐标
     *
     * @return 圆心的 Y 坐标
     */
    private fun calculateCircleCenterY(): Float {
        return selectStepCircleRadius + dpToPx(context, 2) + paddingTop
    }

    /**
     * 绘制对勾
     * Draw check
     *
     * @param canvas 画布
     * @param centerX 圆心的 X 坐标
     * @param centerY 圆心的 Y 坐标
     */
    private fun drawCheck(canvas: Canvas, centerX: Float, centerY: Float) {
        checkPath.reset() // 重置路径
        // 定义勾的起点、中间点和终点
        val startX = centerX - stepCircleRadius * 0.3f // 起点偏移
        val startY = centerY
        val middleX = centerX
        val middleY = centerY + stepCircleRadius * 0.3f // 中间点向下偏移
        val endX = centerX + stepCircleRadius * 0.5f // 终点向右偏移
        val endY = centerY - stepCircleRadius * 0.3f // 终点向上偏移

        // 创建勾的路径
        checkPath.moveTo(startX, startY) // 起点
        checkPath.lineTo(middleX, middleY) // 中间点
        checkPath.lineTo(endX, endY) // 终点

        // 绘制勾
        canvas.drawPath(checkPath, circlePaint)
    }

    /**
     * 循环绘制每个步骤的文本
     */
    private fun drawStepText(canvas: Canvas) {
        val maxWidth = unitX - paddingStart - dpToPx(context, 6)
        // 遍历每个步骤，循环绘制文本
        for (i in 0 until stepText.size) {
            // 计算当前步骤的 X 起始位置
            val startX = unitX * i + paddingStart

            // 分割文本为多行
            val lines = splitTextIntoLines(stepText[i], maxWidth)

            // 计算文本的高度
            val fontMetrics = stepTextPaint.fontMetrics
            val lineHeight = fontMetrics.descent - fontMetrics.ascent
            stepTextPaint.color = getDrawColor(i)
            // 绘制最多两行文本
            drawLimitedLines(canvas, lines, maxWidth, lineHeight, startX)
        }
    }

    /**
     * 绘制最多两行文本，超出部分用省略号代替
     */
    private fun drawLimitedLines(
        canvas: Canvas,
        lines: List<String>,
        maxWidth: Float,
        lineHeight: Float,
        startX: Float
    ) {
        val centerX = startX + (unitX - dpToPx(context, 6)) / 2
        var currentY = selectStepCircleRadius * 2 + lineHeight + paddingTop + stepTextPadding

        if (lines.size > 2) {
            // 取前两行，并在第二行末尾添加省略号
            val firstLine = lines[0]
            var secondLine = lines[1]

            // 确保第二行加上省略号后不超过最大宽度
            while (stepTextPaint.measureText("$secondLine...") > maxWidth) {
                secondLine = secondLine.substring(0, secondLine.length - 1)
            }
            secondLine += "..."

            // 绘制第一行和第二行
            drawCenteredText(canvas, firstLine, centerX, currentY)
            drawCenteredText(canvas, secondLine, centerX, currentY + lineHeight)
        } else {
            // 如果不超过两行，直接绘制所有行
            for (line in lines) {
                drawCenteredText(canvas, line, centerX, currentY)
                currentY += lineHeight
            }
        }
        drawBound(canvas, lines[0], centerX)
    }

    /**
     * Draw bound
     * 计算文本的矩形边界
     * @param text
     * @param centerX
     */
    private fun drawBound(canvas: Canvas, text: String, centerX: Float) {
        //取第一行
        val textWidth = stepTextPaint.measureText(text)
        val boundWidth = if (textWidth < selectStepCircleRadius * 2) {
            selectStepCircleRadius * 2
        } else {
            textWidth
        }
        val textBound = RectF(
            centerX - boundWidth / 2,
            paddingTop.toFloat(),
            centerX - boundWidth / 2 + boundWidth,
            height.toFloat() - paddingBottom
        )
//        canvas.drawRect(textBound, linePaint)
        textBoundsCache.add(textBound)
    }

    /**
     * 在指定位置绘制居中文本
     */
    private fun drawCenteredText(
        canvas: Canvas,
        text: String,
        centerX: Float,
        centerY: Float
    ) {
        val textWidth = stepTextPaint.measureText(text)
        canvas.drawText(text, centerX - textWidth / 2, centerY, stepTextPaint)
    }

    /**
     * 计算View 的高度
     * Find longest string
     *
     * @param array
     * @return
     */
    private fun findLongestStringAndMeasure(array: Array<String>): Pair<Int, Int> {
        val str = array.fold(array[0]) { longest, current ->
            if (current.length >= longest.length) current else longest
        }
        // 测量文本的宽高
        val bounds = Paint.FontMetrics()
        stepTextPaint.getFontMetrics(bounds)
        val textWidth = stepTextPaint.measureText(str)
        val textHeight = bounds.descent - bounds.ascent

        val roundedWidth = ceil(textWidth.toDouble()).toInt()
        val roundedHeight = ceil(textHeight.toDouble()).toInt()

        return roundedWidth to roundedHeight
    }

    /**
     * 将文本分割为多行
     *
     * @param text 要分割的文本
     * @param maxWidth 每行的最大宽度
     * @return 分割后的文本行列表
     */
    private fun splitTextIntoLines(text: String, maxWidth: Float): List<String> {
        val lines = mutableListOf<String>()
        var currentLine = ""
        // 遍历每个字符（支持中文和英文）
        for (char in text) {
            val testLine = if (currentLine.isEmpty()) char.toString() else "$currentLine$char"
            val testLineWidth = stepTextPaint.measureText(testLine)
            if (testLineWidth <= maxWidth) {
                // 如果未超出宽度，则将字符添加到当前行
                currentLine = testLine
            } else {
                // 如果超出宽度，则保存当前行并开始新的一行
                lines.add(currentLine)
                currentLine = char.toString()
            }
        }
        // 添加最后一行
        if (currentLine.isNotEmpty()) {
            lines.add(currentLine)
        }
        return lines
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let { motionEvent ->
            when (motionEvent.action) {
                MotionEvent.ACTION_DOWN -> {
                    // 处理按下事件（可选）
                    LogUtil.d("按下事件")
                    return true // 消费按下事件
                }

                MotionEvent.ACTION_UP -> {
                    val x = motionEvent.x
                    val y = motionEvent.y
                    LogUtil.d("x = ${x}，y = $y")
                    // 检查是否点击到文本
                    for ((index, bounds) in textBoundsCache.withIndex()) {
                        if (bounds.contains(x, y)) {
                            LogUtil.d("点击了 $index")
                            selectStep = index + 1
                            onStepClickListener?.invoke(step, selectStep)
                            invalidate() // 触发重绘
                            performClick() // 支持无障碍功能
                            return true // 消费事件
                        }
                    }
                }

                else -> {
                    // 其他事件（如 ACTION_MOVE）可以忽略
                    return super.onTouchEvent(event)
                }
            }
        }
        return super.onTouchEvent(event)
    }

    override fun performClick(): Boolean {
        // 调用父类的 performClick 方法以支持无障碍功能
        super.performClick()
        // 在这里可以添加额外的点击逻辑
        return true
    }

    /**
     * 下一步 ,选择的也选择切换到下一步
     * Set on step next listener
     *
     * @param step
     * @param selectStep
     */
    fun setNextStep(step: Int, selectStep: Int) {
        if (step < maxStep + 2 && selectStep < maxStep + 2) {
            this.step = step
            this.selectStep = selectStep
            invalidate()
        } else {
            throw IllegalArgumentException("step or maxStep  is error,step or selectStep not more than 6")
        }
    }

    @Retention(AnnotationRetention.SOURCE)
    @IntDef(LINE_SOLID, LINE_DOTTED)
    annotation class LineMode {
        companion object {
            const val LINE_SOLID = 0
            const val LINE_DOTTED = 1
        }
    }
}